package net.oschina.allchat.protocol.core;

import java.util.StringTokenizer;


public final class ChatId {
	private String name;
	private String domain;
	private String resource;
	
	private static final char CHAR_AT = '@';
	private static final char CHAR_SLASH = '/';
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getDomain() {
		return domain;
	}
	
	public void setDomain(String domain) {
		this.domain = domain;
	}
	
	public String getResource() {
		return resource;
	}
	
	public void setResource(String resource) {
		this.resource = resource;
	}
	
	@Override
	public int hashCode() {
		int hash = 7;
		
		hash += 31 * hash + (name == null ? 0 : name.hashCode());
		hash += 31 * hash + (domain == null ? 0 : domain.hashCode());
		hash += 31 * hash + (resource == null ? 0 : resource.hashCode());
		
		return hash;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		
		if (obj == this) {
			return true;
		}
		
		if (obj instanceof ChatId) {
			ChatId other = (ChatId)obj;
			
			if (!equalsEvenNull(this.name, other.name))
				return false;
			
			if (this.domain == null || other.domain == null) {
				return false;
			}
			
			if (!this.domain.equals(other.domain)) {
				return false;
			}
			
			if (!equalsEvenNull(this.resource, other.resource))
				return false;
			
		}
		
		return false;
	}
	
	private boolean equalsEvenNull(Object obj1, Object obj2) {
		if (obj1 != null) {
			return obj1.equals(obj2);
		} else {
			return obj2 == null;
		}
	}
	
	@Override
	public String toString() {
		validateChatId();
		
		StringBuilder builder = new StringBuilder();
		
		if (name != null)
			builder.append(name).append(CHAR_AT);
		builder.append(domain);
		if (resource != null)
			builder.append(CHAR_SLASH).append(resource);
		
		return builder.toString();
	}
	
	public String getBareIdString() {
		if (domain == null)
			throw new IllegalStateException("Null domain");

		if (name == null)
			return domain;
		else
			return String.format("%s%s%s", name, CHAR_AT, domain);
	}
	
	public static ChatId parse(String chatIdString) {
		ChatId chatId = new ChatId();
		chatId.fromChatIdString(chatIdString);
		
		return chatId;
	}
	
	private void validateChatId() {
		if (name != null && name.length() > 64)
			throw new IllegalArgumentException("Name identifier of ChatID mustn't be more than 64 bytes in length");
		
		if (domain != null && domain.length() > 128)
			throw new IllegalArgumentException("Domain identifier of ChatID mustn't be more than 128 bytes in length");
		
		if (resource != null && resource.length() > 64)
			throw new IllegalArgumentException("Resource identifier of ChatID mustn't be more than 64 bytes in length");
		
		// TODO ChatID format validation
	}
	
	private void fromChatIdString(String chatId) {
		if (chatId.indexOf(CHAR_AT) == -1) {
			if (chatId.indexOf(CHAR_SLASH) != -1)
				throw new MalformedChatIdException();
			
			domain = chatId;
		} else {
			StringTokenizer atTokenizer = new StringTokenizer(chatId, String.valueOf(CHAR_AT));
			if (atTokenizer.countTokens() != 2)
				throw new MalformedChatIdException();
			
			name = atTokenizer.nextToken();
			String domainAndResource = atTokenizer.nextToken();
			
			if (domainAndResource.indexOf(CHAR_SLASH) == -1) {
				domain = domainAndResource;
			} else {
				StringTokenizer slashTokenizer = new StringTokenizer(domainAndResource, String.valueOf(CHAR_SLASH));
				if (slashTokenizer.countTokens() != 2)
					throw new MalformedChatIdException();
				
				domain = slashTokenizer.nextToken();
				resource = slashTokenizer.nextToken();
			}
		}
		
		try {
			validateChatId();
		} catch (IllegalArgumentException e) {
			throw new MalformedChatIdException(e);
		}		
	}
	
}
